#pragma once

namespace Pdf
{
    template <typename ObjectType>
    Object::Ptr SimpleFactoryT<ObjectType>::create()
    {    return new ObjectType( data );    }

    template <typename ObjectType>
    void SimpleFactoryT<ObjectType>::append(char c)
    {    data.push_back( c );    }

    // =====================================================================

    template <typename ObjectType>
    Object::Ptr ContainerFactoryT<ObjectType>::create()
    {    return new ObjectType( data );    }

    template <typename ObjectType>
    void ContainerFactoryT<ObjectType>::append(Object::Ptr obj)
    {
        Keyword::Ptr r = cast<Keyword*>( obj );

        if ( r != 0 && r->get() == "R" )
        {
			Integer::Value gen = cast<Integer::Value>( pop() );
            Integer::Value id  = cast<Integer::Value>( pop() );
            obj = new Reference( Reference::Value( id, gen ) );
        }

        push( obj );
    };

    template <typename ObjectType>
    void ContainerFactoryT<ObjectType>::push(Object::Ptr obj)
    {    data.push_back( obj );    };

    template <typename ObjectType>
    Object::Ptr ContainerFactoryT<ObjectType>::pop()
    {
        Object::Ptr obj = data.back();
        data.pop_back();
        return obj;
    };

    // =====================================================================

    inline TokenFactory::TokenFactory() : state(stFirst)
    {    }

    inline void TokenFactory::append(char c)
    {
        switch (state)
        {
        case stFirst:
            switch ( c )
            {
            case '+':
            case '-':
            case '0':
            case '1':
            case '2':
            case '3':
            case '4':
            case '5':
            case '6':
            case '7':
            case '8':
            case '9':
                state = stInteger;
                break;
            case '.':
                state = stReal;
                break;
            default:
                state = stKeyword;
            }
            break;
        case stInteger:
            switch ( c )
            {
            case '0':
            case '1':
            case '2':
            case '3':
            case '4':
            case '5':
            case '6':
            case '7':
            case '8':
            case '9':
                break;
            case '.':
                state = stReal;
                break;
            default:
                state = stKeyword;
            }
            break;
        case stReal:
            switch ( c )
            {
            case '0':
            case '1':
            case '2':
            case '3':
            case '4':
            case '5':
            case '6':
            case '7':
            case '8':
            case '9':
                break;
            default:
                state = stKeyword;
            }
            break;
        }
        data.push_back( c );
    }

    inline Object::Ptr TokenFactory::create()
    {
        if (data.empty() || data == "null")
            return new Null();

        switch (state)
        {
        case stInteger:
            return new Integer( _atoi64( data.c_str() ) );
        case stReal:
            return new Real( atof( data.c_str() ) );
        case stKeyword:
            return new Keyword( data );
        }

		assert(false);
        return 0;
    }
}